home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 3006 / 3006.xpi / components / dhCore.js < prev    next >
Text File  |  2010-01-15  |  53KB  |  1,656 lines

  1. /******************************************************************************
  2.  *            Copyright (c) 2006-2009 Michel Gutierrez. All Rights Reserved.
  3.  ******************************************************************************/
  4.  
  5. /**
  6.  * Constants.
  7.  */
  8.  
  9. const NS_CORE_CID = Components.ID("{e4e95e7f-12f1-4b21-8155-82eb22b88c86}");
  10. const NS_CORE_PROG_ID = "@downloadhelper.net/core;1";
  11. const DHNS = "http://downloadhelper.net/1.0#";
  12. const CICORE = Components.interfaces.dhICore;
  13. const CTRL_KEY = 1;
  14. const SHIFT_KEY = 2;
  15. const ALT_KEY = 4;
  16. const META_KEY = 8;
  17.  
  18. var Util=null;
  19.  
  20. /**
  21. * Object constructor
  22. */
  23. function Core() {
  24.     try {
  25.         //dump("[Core] constructor\n");
  26.         this.promptService=Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  27.                                               .getService(Components.interfaces.nsIPromptService);
  28.         var prefService=Components.classes["@mozilla.org/preferences-service;1"]
  29.                                            .getService(Components.interfaces.nsIPrefService);
  30.         this.pref=prefService.getBranch("dwhelper.");
  31.         this.prefBranch2=this.pref.QueryInterface(Components.interfaces.nsIPrefBranch2);
  32.         this.prefBranch2.addObserver("", this, false);
  33.         this.updateProcessorKeyMap();
  34.         this.observerService =
  35.             Components.classes["@mozilla.org/observer-service;1"]
  36.                 .getService(Components.interfaces.nsIObserverService);
  37.         this.listMgr=Components.classes["@downloadhelper.net/media-list-manager"]
  38.                                         .getService(Components.interfaces.dhIMediaListMgr);
  39.         this.dlMgr=Components.classes["@downloadhelper.net/download-manager;1"]
  40.                                         .getService(Components.interfaces.dhIDownloadMgr);
  41.         this.cvMgr=Components.classes["@downloadhelper.net/convert-manager-component"]
  42.                                           .getService(Components.interfaces.dhIConvertMgr);
  43.         this.smartNamer = Components.classes["@downloadhelper.net/smart-namer;1"]
  44.                                         .getService(Components.interfaces.dhISmartNamer);
  45.  
  46.         this.regMenus=[];
  47.         this.probes=[];
  48.         this.entries=[];
  49.         this.processors=[];
  50.         this.ctxItems=[];
  51.         this.blacklist=[];
  52.         
  53.         this.updateBlackList();
  54.         this.shareBlackList();
  55.  
  56.         this.observerService.addObserver(this,"http-on-modify-request",false);
  57.         this.observerService.addObserver(this,"http-on-examine-response",false);
  58.         this.observerService.addObserver(this,"quit-application",false);
  59.     } catch(e) {
  60.         dump("[Core] !!! constructor: "+e+"\n");
  61.     }
  62. }
  63.  
  64. Core.prototype = {
  65. }
  66.  
  67. Core.prototype.registerMenu=function(menupopup,menutype) {
  68.     //dump("[Core] registerMenu("+menupopup+","+menutype+")\n");
  69.     if(menutype==Components.interfaces.dhICore.MENU_TYPE_DOWNLOAD) {
  70.         var button=null;
  71.         var buttonId=menupopup.getAttribute("dh-controlled-button");
  72.         if(buttonId!=null && buttonId.length>0) {
  73.             button=menupopup.ownerDocument.getElementById(buttonId);
  74.             if(button && !button.hasAttribute("dh-installed-handler")) {
  75.                 function Listener(core,window,button) {
  76.                     this.core=core;
  77.                     this.window=window;
  78.                     this.button=button;
  79.                 }
  80.                 Listener.prototype={
  81.                     handleEvent: function(event) {
  82.                         if(event.target==this.button)
  83.                             this.core.buttonClicked(this.window);
  84.                     }
  85.                 }
  86.                 var buttonTarget=button.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  87.                 buttonTarget.addEventListener("command",new Listener(this,menupopup.ownerDocument.defaultView,button),false,false);
  88.                 button.setAttribute("dh-installed-handler","true");
  89.             }
  90.         }
  91.         var hideParentIfEmpty=false;
  92.         if(menupopup.getAttribute("hide-parent-if-empty")=="true")
  93.             hideParentIfEmpty=true;
  94.         this.regMenus.push({
  95.             //menupopup: menupopup.QueryInterface(Components.interfaces.nsISupportsWeakReference).GetWeakReference(),
  96.             menupopup: menupopup,
  97.             menutype:menutype,
  98.             window: menupopup.ownerDocument.defaultView,
  99.             button: button,
  100.             hideParentIfEmpty: hideParentIfEmpty
  101.         });
  102.         try {
  103.             var window=menupopup.ownerDocument.defaultView;
  104.             var document=window.contentDocument;
  105.             this.updateMenus(document,window);
  106.         } catch(e) {}
  107.         //dump("=>"+this.regMenus.length+"\n");
  108.     } else if(menutype==Components.interfaces.dhICore.MENU_TYPE_SYSTEM) {
  109.         menupopup=menupopup.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  110.         function Listener(core) {
  111.             this.core=core;
  112.         }
  113.         Listener.prototype={
  114.             handleEvent: function(event) {
  115.                 if(event.target.getAttribute("class")=="SystemMenu")
  116.                     this.core.updateSystemMenu(event.target);
  117.             }
  118.         }
  119.         menupopup.addEventListener("popupshowing",new Listener(this),false,false);        
  120.     }
  121. }
  122.  
  123. Core.prototype.unregisterMenu=function(menupopup) {
  124.     //dump("[Core] unregisterMenu("+menupopup+")\n");    
  125.     var found=false;
  126.     for(var i in this.regMenus) {
  127.         if(this.regMenus[i].menupopup==menupopup) {
  128.             this.regMenus.splice(i,1);
  129.             found=true;
  130.             //dump("=>"+this.regMenus.length+"\n");
  131.             break;
  132.         }
  133.     }
  134.     if(!found) {
  135.         menupopup=menupopup.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  136.         // must be a system menu, but no way to remove event listener
  137.     }
  138. }
  139.  
  140. Core.prototype.registerProbe=function(probe) {
  141.     //dump("[Core] registerProbe("+probe+")\n");
  142.     this.probes.push(probe);
  143. }
  144.  
  145. Core.prototype.unregisterProbe=function(probe) {
  146.     //dump("[Core] unregisterProbe("+probe+")\n");
  147.     for(var i in this.probes) {
  148.         if(this.probes[i]==probe) {
  149.             this.probes.splice(i,1);
  150.             break;
  151.         }
  152.     }
  153. }
  154.  
  155. Core.prototype.observe=function(subject, topic , data) {
  156.     //dump("[Core] observe("+subject+","+topic+","+data+")\n");    
  157.     try {
  158.     switch(topic) {
  159.         case "http-on-modify-request":
  160.             var channel=subject.QueryInterface(Components.interfaces.nsIHttpChannel);
  161.             if(channel.requestMethod!="GET")
  162.                 return;
  163.             var request=subject.QueryInterface(Components.interfaces.nsIRequest);
  164.             //dump("[Core] observe/http-on-modify-request "+request.name+"\n");
  165.             if(this.listMgr.checkCurrentURL(request.name)) {
  166.                 return;
  167.             }
  168.             for(var i in this.probes) {
  169.                 var probe=this.probes[i];
  170.                 if(probe.handleRequest) {
  171.                     try {
  172.                         probe.handleRequest(request);
  173.                     } catch(e) {
  174.                     }
  175.                 }
  176.             }
  177.             break;
  178.             
  179.         case "http-on-examine-response":
  180.             var request=subject.QueryInterface(Components.interfaces.nsIRequest);
  181.             //dump("[Core] observe/http-on-examine-response "+request.name+"\n");
  182.             if(this.listMgr.checkCurrentURL(request.name)) {
  183.                 try {
  184.                     var channel=subject.QueryInterface(Components.interfaces.nsIHttpChannel);
  185.                     var location=channel.getResponseHeader("Location");
  186.                     if(location!=null) {
  187.                         this.listMgr.addCurrentURL(location);
  188.                     }
  189.                 } catch(e) {}
  190.                 return;
  191.             }
  192.             for(var i in this.probes) {
  193.                 var probe=this.probes[i];
  194.                 if(probe.handleResponse) {
  195.                     try {
  196.                         probe.handleResponse(request);
  197.                     } catch(e) {
  198.                         dump("!!! [Core] observe("+subject+","+topic+","+data+"): "+e+"\n");
  199.                     }
  200.                 }
  201.             }
  202.             break;
  203.             
  204.         case "nsPref:changed":
  205.             if(data=="processor-keymap")
  206.                 this.updateProcessorKeyMap();
  207.             if(data=="disable-dwcount-cookie")
  208.                 this.removeDownloadCookie();
  209.             if(data=="media-host-blacklist")
  210.                 this.updateBlackList();
  211.             break;
  212.             
  213.         case "quit-application":
  214.             //dump("[Core] observe/quit-application\n");
  215.             this.prefBranch2.removeObserver("",this);
  216.             this.observerService.removeObserver(this,"http-on-modify-request");
  217.             this.observerService.removeObserver(this,"http-on-examine-response");
  218.             this.observerService.removeObserver(this,"quit-application");
  219.             break;
  220.     }
  221.     } catch(e) {
  222.         dump("!!! [Core] observe("+subject+","+topic+","+data+"): "+e+"\n");    
  223.     }
  224. }
  225.  
  226. Core.prototype.handleEvent=function(event) {
  227.     //dump("[Core] handleEvent("+event.type+"/"+event.eventPhase+"/"+event.target+")\n");
  228.     var window=event.target.defaultView;
  229.     //dump("Window="+window+"\n");
  230.     switch(event.type) {
  231.         case "select":
  232.             //dump("select - "+event.target+"\n");
  233.             try {
  234.                 var tabbrowser=event.target.parentNode.parentNode;
  235.                 if(tabbrowser.nodeName=="tabbrowser") {
  236.                     var tab=tabbrowser.selectedTab;
  237.                     var browser=tabbrowser.getBrowserForTab(tab);
  238.                     var document=browser.contentDocument;
  239.                     this.updateMenus(document,event.target.ownerDocument.defaultView);
  240.                 }
  241.             } catch(e) {
  242.                 dump("!!! [Core] handleEvent(select): "+e+"\n");
  243.             }
  244.             break;
  245.         default:
  246.             dump("[Core] handleEvent("+event.type+"/"+event.eventPhase+"/"+event.target+")\n");
  247.     }
  248. }
  249.  
  250. Core.prototype.cleanupEntriesForDocument=function(document,window) {
  251.     //dump("[Core] cleanupEntriesForDocument("+document.URL+",window)\n");
  252.     try {
  253.         var tbd=[];
  254.         for(var i in this.entries) {
  255.             var entry=this.entries[i];
  256.             var entryType=Util.getPropsString(entry,"entry-type");
  257.             if(entryType=="document") {
  258.                 if(window) {
  259.                     if(entry.has("window") && entry.has("document")) {
  260.                         var entryWindow=entry.get("window",Components.interfaces.nsIDOMWindow);
  261.                         var entryDocument=entry.get("document",Components.interfaces.nsIDOMDocument);
  262.                         if(entryWindow==window && entryDocument==document) {
  263.                             tbd.push(entry);
  264.                         }
  265.                     }
  266.                 } else {
  267.                     tbd.push(i);
  268.                 }
  269.             }
  270.         }
  271.         for(var i in tbd) {
  272.             this.entries.splice(this.entries.indexOf(tbd[i]),1);
  273.         }
  274.     } catch(e) {
  275.         dump("!!! [Core] cleanupEntriesForDocument: "+e+"\n");
  276.     }
  277. }
  278.  
  279. Core.prototype.updateEntriesForDocument=function(document,window) {
  280.     //dump("[Core] updateEntriesForDocument("+document.URL+")\n");
  281.     try {
  282.         for(var i in this.probes) {
  283.             var entry=null;
  284.             try {
  285.                 entry=this.probes[i].handleDocument(document,window);
  286.             } catch(e) {}
  287.             if(entry) {
  288.                 Util.setPropsString(entry,"entry-type","document");
  289.                 Util.setPropsString(entry,"document-url",document.URL);
  290.                 entry.set("document",document);
  291.                 entry.set("window",window);
  292.                 if(this.filterBlackList(entry)) {
  293.                     this.entries.push(entry);
  294.                 }
  295.             }
  296.         }
  297.     } catch(e) {
  298.         dump("!!! [Core] updateEntriesForDocument("+document.URL+"): "+e+"\n");
  299.     }
  300. }
  301.  
  302. Core.prototype.addEntryForDocument=function(entry,document,window) {
  303.     try {
  304.         //dump("[Core] addEntryForDocument(entry,"+document.URL+",window)\n");
  305.         Util.setPropsString(entry,"entry-type","document");
  306.         Util.setPropsString(entry,"document-url",document.URL);
  307.         entry.set("document",document);
  308.         entry.set("window",window);
  309.         if(this.filterBlackList(entry)) {
  310.             this.smartNamer.updateEntry(entry);
  311.             this.entries.push(entry);
  312.             this.updateMenus(document,window);
  313.         }
  314.     } catch(e) {
  315.         dump("!!! [Core] addEntryForDocument("+document.URL+"): "+e+"\n");
  316.     }
  317. }
  318.  
  319. Core.prototype.addEntry=function(entry) {
  320.     try {
  321.         //dump("[Core] addEntry(entry)\n");
  322.         var mediaUrl=Util.getPropsString(entry,"media-url");
  323.         if(mediaUrl)
  324.             this.cleanupExpirableEntriesForMediaUrl(mediaUrl);
  325.         Util.setPropsString(entry,"entry-type","expirable");
  326.         Util.setPropsString(entry,"creation-date",""+new Date().getTime());
  327.         if(this.filterBlackList(entry)) {
  328.             this.smartNamer.updateEntry(entry);
  329.             this.entries.push(entry);
  330.             this.updateMenus(null,null);
  331.         }
  332.     } catch(e) {
  333.         dump("!!! [Core] addEntry(): "+e+"\n");
  334.     }
  335. }
  336.  
  337. Core.prototype.filterBlackList=function(entry) {
  338.     var url=Util.getPropsString(entry,"media-url");
  339.     if(url==null)
  340.         return true;
  341.     for(var i in this.blacklist) {
  342.         if(new RegExp("//[^/]*"+this.blacklist[i]+"/").test(url)) {
  343.             //dump("[Core] filterBlackList(): filtered out "+url+"\n");
  344.             return false;
  345.         }
  346.     }
  347.     return true;
  348. }
  349.  
  350. Core.prototype.cleanupExpirableEntriesForMediaUrl=function(url) {
  351.     //dump("[Core] cleanupExpirableEntriesForMediaUrl("+url+")\n");
  352.     var tbd=[];
  353.     for(var i=0;i<this.entries.length;i++) {
  354.         var entry=this.entries[i];
  355.         if(Util.getPropsString(entry,"entry-type")=="expirable" &&
  356.                 Util.getPropsString(entry,"media-url")==url) {
  357.             //dump("[Core] cleanupExpirableEntriesForMediaUrl("+url+") found\n");
  358.             tbd.push(entry);
  359.         }
  360.     }
  361.     for(var i in tbd)
  362.         this.entries.splice(this.entries.indexOf(tbd[i]),1);    
  363. }
  364.  
  365. Core.prototype.getTopDocument=function(document) {
  366.     var topDocument=null;
  367.     if(document && document.defaultView) {
  368.         var obj=document.defaultView;
  369.         while(obj) {
  370.             topDocument=obj.document;
  371.             if(obj==obj.parent)
  372.                 obj=null;
  373.             else
  374.                 obj=obj.parent;
  375.         }
  376.     }
  377.     return topDocument;
  378. }
  379.  
  380. Core.prototype.updateMenus=function(document,window) {
  381.     //dump("[Core] updateMenus("+(document?document.URL:null)+","+(window?window.content.document.URL:"window")+")\n");
  382.     var topDocument=this.getTopDocument(document);
  383.     try {
  384.         this.cleanupExpiredEntries();
  385.         for(var i in this.regMenus) {
  386.             var menu=this.regMenus[i];
  387.             if(window==null || window==menu.window) {
  388.                 if(menu.menupopup) {
  389.                     //var menupopup=menu.menupopup.QueryReferent(Components.interfaces.nsIDOMElement);
  390.                     var menupopup=menu.menupopup;
  391.                     if(menupopup.ownerDocument.defaultView && menupopup.ownerDocument.defaultView.content && 
  392.                             menupopup.ownerDocument.defaultView.content.document && 
  393.                             menupopup.ownerDocument.defaultView.content.document.URL) {
  394.                         pageUrl=menupopup.ownerDocument.defaultView.content.document.URL;
  395.                     }
  396.                     this.clearMenu(menupopup);
  397.                     var gotEntries=false;
  398.                     for(var j in this.entries) {
  399.                         var entry=this.entries[j];
  400.                         if(entry.has("document")) {
  401.                             var entryDocument=entry.get("document",Components.interfaces.nsIDOMDocument);
  402.                             if(document!=null && topDocument!=null && topDocument!=this.getTopDocument(entryDocument) && entryDocument!=document) {
  403.                                 continue;
  404.                             }
  405.                             if(document==null && menu.window.content && menu.window.content.document!=entryDocument) {
  406.                                 continue;
  407.                             }
  408.                         }
  409.                         var entryWindow=null;
  410.                         if(entry.has("window"))
  411.                             entryWindow=entry.get("window",Components.interfaces.nsIDOMWindow);
  412.                         if(window==null || entryWindow==null || window==entryWindow) {
  413.                             var classes=[];
  414.                             var menuitem;
  415.                             if(this.pref.getBoolPref("extended-download-menu")) {
  416.                                 menuitem=this.makeDownloadMenu(menupopup,entry,classes);
  417.                             } else {
  418.                                 menuitem=this.makeDownloadMenuitem(menupopup,entry,classes);
  419.                             }
  420.  
  421.                             if(entry.has("mouse-listener")) {
  422.                                 function MouseListener(entry,probeListener) {
  423.                                     this.entry=entry;
  424.                                     this.probeListener=probeListener;
  425.                                 }
  426.                                 MouseListener.prototype={
  427.                                     handleEvent: function(event) {
  428.                                         switch(event.type) {
  429.                                             case "mouseover":
  430.                                                 this.probeListener.mouseOver(this.entry);
  431.                                                 break;
  432.                                             case "mouseout":
  433.                                                 this.probeListener.mouseOut(this.entry);
  434.                                                 break;
  435.                                         }
  436.                                     }
  437.                                 }
  438.                                 var listener=new MouseListener(entry,entry.get("mouse-listener",Components.interfaces.dhIProbeMouseListener));
  439.                                 var eventTarget=menuitem.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  440.                                 eventTarget.addEventListener("mouseover",listener,false,false);
  441.                                 eventTarget.addEventListener("mouseout",listener,false,false);
  442.                             }
  443.                             var debugTooltip=false;
  444.                             try {
  445.                                 debugTooltip=this.pref.getBoolPref("menu-tooltip-debug");
  446.                             } catch(e) {}
  447.                             if(debugTooltip) {
  448.                                 var tooltipText="";
  449.                                 var keys=entry.getKeys({});
  450.                                 for(var key in keys) {
  451.                                     tooltipText+="["+keys[key]+"] ";
  452.                                     var value=Util.getPropsString(entry,keys[key]);
  453.                                     if(value)
  454.                                         tooltipText+=value;
  455.                                     else
  456.                                         tooltipText+="...";
  457.                                     tooltipText+="\n";
  458.                                 }
  459.                                 menuitem.setAttribute("tooltiptext",tooltipText);                                
  460.                             } else if(entry.has("media-url")) {
  461.                                 var mediaUrl=Util.getPropsString(entry,"media-url");
  462.                                 menuitem.setAttribute("tooltiptext",mediaUrl);
  463.                             }
  464.                             var highlightMFCP=true;
  465.                             try {
  466.                                 highlightMFCP=this.pref.getBoolPref("highlight-media-from-current-page");
  467.                             } catch(e) {}
  468.                             if(highlightMFCP && entry.has("page-url")) {
  469.                                 var pageUrl=Util.getPropsString(entry,"page-url");
  470.                                 var inCurrentWindow=false;
  471.                                 if(document) {
  472.                                     if(document.URL==pageUrl)
  473.                                         inCurrentWindow=true;
  474.                                 } else {
  475.                                     if(menu.window.content && menu.window.content.document.URL==pageUrl)
  476.                                         inCurrentWindow=true;
  477.                                 }
  478.                                 if(inCurrentWindow)
  479.                                     classes.push("dwhelper-mediainpage");
  480.                             }
  481.                             menuitem.setAttribute("class",classes.join(" "));
  482.                             menupopup.appendChild(menuitem);
  483.                             gotEntries=true;
  484.                         }
  485.                     }
  486.                     if(menu.button) {
  487.                         menu.button.removeAttribute("image");
  488.                         var butClass=menu.button.getAttribute("class");
  489.                         butClass=butClass.replace(/ on-noanim| on| off/,"");
  490.                         if(gotEntries) {
  491.                             var ia=true;
  492.                             try {
  493.                                 ia=this.pref.getBoolPref("icon-animation");
  494.                             } catch(e) {}
  495.                             if(ia)
  496.                                 butClass+=" on";
  497.                             else
  498.                                 butClass+=" on-noanim";
  499.                             menu.button.setAttribute("type","menu-button");
  500.                         } else {
  501.                             butClass+=" off";
  502.                             menu.button.removeAttribute("type");
  503.                         }
  504.                         menu.button.setAttribute("class",butClass);
  505.                     }
  506.                     if(menu.hideParentIfEmpty && menupopup.parentNode) {
  507.                         if(gotEntries)
  508.                             menupopup.parentNode.setAttribute("hidden","false");
  509.                         else
  510.                             menupopup.parentNode.setAttribute("hidden","true");
  511.                     }
  512.                 }
  513.             } 
  514.         }
  515.     } catch(e) {
  516.         dump("!!! [Core] updateMenus(): "+e+"\n");
  517.     }
  518. }
  519.  
  520. Core.prototype.makeDownloadMenuitem=function(menupopup,entry,classes) {
  521.     var menuitem=menupopup.ownerDocument.createElement("menuitem");
  522.     var eventTarget=menuitem.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  523.     var label=Util.getPropsString(entry,"label");
  524.     if(label)
  525.         menuitem.setAttribute("label",label);
  526.     var icon=Util.getPropsString(entry,"icon-url");
  527.     if(icon) {
  528.         menuitem.setAttribute("image",icon);
  529.         classes.push("menuitem-iconic");
  530.         classes.push("controler-entry");
  531.     }
  532.     
  533.     function CommandListener(entry,commandListener) {
  534.         this.entry=entry;
  535.         this.commandListener=commandListener;
  536.     }
  537.     CommandListener.prototype={
  538.         handleEvent: function(event) {
  539.             if(event.type=="command") {
  540.                 var key=(event.ctrlKey?CTRL_KEY:0) |
  541.                     (event.shiftKey?SHIFT_KEY:0) |
  542.                     (event.altKey?ALT_KEY:0) |
  543.                     (event.metaKey?META_KEY:0);
  544.                 this.commandListener.handleCommand(this.entry,key);
  545.             }
  546.         }
  547.     }
  548.     var commandListener=new CommandListener(entry,this);
  549.     eventTarget.addEventListener("command",commandListener,false,false);
  550.     return menuitem;
  551. }
  552.  
  553. Core.prototype.makeDownloadMenu=function(menupopup,entry,classes) {
  554.     var uiDocument=menupopup.ownerDocument;
  555.     var menuitem=uiDocument.createElement("menu");
  556.     var menupopup1=uiDocument.createElement("menupopup");
  557.     menuitem.appendChild(menupopup1);
  558.  
  559.     function CommandListener(core,entry,processor) {
  560.         this.core=core;
  561.         this.entry=entry;
  562.         this.processor=processor;
  563.     }
  564.     CommandListener.prototype={
  565.         handleEvent: function(event) {
  566.             try {
  567.                 this.core.processEntry(this.processor,this.entry);
  568.             } catch(e) {
  569.                 dump("!!! [Core/DownloadMenu] CommandListener.handleEvent(): "+e+"\n");
  570.             }
  571.             event.stopPropagation(); 
  572.         }
  573.     }
  574.     
  575.     var i=this.getProcessors().enumerate();
  576.     while(i.hasMoreElements()) {
  577.         var processor=i.getNext().QueryInterface(Components.interfaces.dhIProcessor);
  578.         if(processor.canHandle(entry)) {
  579.             var menuitem1=uiDocument.createElement("menuitem");
  580.             menuitem1.setAttribute("label",processor.title);
  581.             menuitem1.setAttribute("tooltiptext",processor.description);
  582.             menuitem1.setAttribute("class","download-processor-entry");
  583.             menuitem1.QueryInterface(Components.interfaces.nsIDOMNSEventTarget).
  584.                 addEventListener("command",new CommandListener(this,entry,processor),false,false);
  585.             menupopup1.appendChild(menuitem1);
  586.         }
  587.     }
  588.  
  589.     var eventTarget=menuitem.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  590.     var label=Util.getPropsString(entry,"label");
  591.     if(label)
  592.         menuitem.setAttribute("label",label);
  593.     var icon=Util.getPropsString(entry,"icon-url");
  594.     if(icon) {
  595.         menuitem.setAttribute("image",icon);
  596.         classes.push("menu-iconic");
  597.         classes.push("controler-entry");
  598.     }
  599.     
  600.     function ClickListener(entry,commandListener) {
  601.         this.entry=entry;
  602.         this.commandListener=commandListener;
  603.     }
  604.     ClickListener.prototype={
  605.         handleEvent: function(event) {
  606.             if(event.target.localName=="menu" && event.type=="click") {
  607.                 var key=(event.ctrlKey?CTRL_KEY:0) |
  608.                     (event.shiftKey?SHIFT_KEY:0) |
  609.                     (event.altKey?ALT_KEY:0) |
  610.                     (event.metaKey?META_KEY:0);
  611.                 event.target.parentNode.hidePopup();
  612.                 this.commandListener.handleCommand(this.entry,key);
  613.             }
  614.         }
  615.     }
  616.     var commandListener=new ClickListener(entry,this);
  617.     eventTarget.addEventListener("click",commandListener,false,false);    
  618.     return menuitem;
  619. }
  620.  
  621. Core.prototype.clearMenu=function(menupopup) {
  622.     this.deepRemoveChildren(menupopup);
  623. }
  624.  
  625. Core.prototype.deepRemoveChildren=function(element) {
  626.     if(element==null)
  627.         return;
  628.     while(element.firstChild) {
  629.         var child=element.firstChild;
  630.         this.deepRemoveChildren(child);
  631.         element.removeChild(child);
  632.     }
  633. }
  634.  
  635. Core.prototype.cleanupExpiredEntries=function() {
  636.     //dump("[Core] cleanupExpiredEntries()\n");
  637.     var expireTimeout=60;
  638.     try {
  639.         expireTimeout=this.pref.getIntPref("menu-expiration");
  640.     } catch(e) {}
  641.     var timeNow=new Date().getTime();
  642.     var tbd=[];
  643.     for(var i=0;i<this.entries.length;i++) {
  644.         var entry=this.entries[i];
  645.         if(Util.getPropsString(entry,"entry-type")=="expirable") {
  646.             var created=parseInt(Util.getPropsString(entry,"creation-date"));
  647.             if(timeNow>created+expireTimeout*1000) {
  648.                 //dump("[Core] cleanupExpiredEntry(): removed "+Util.getPropsString(entry,"media-url")+"\n");
  649.                 tbd.push(entry);
  650.             }
  651.         }
  652.     }
  653.     for(var i in tbd)
  654.         this.entries.splice(this.entries.indexOf(tbd[i]),1);    
  655. }
  656.  
  657. Core.prototype.registerWindow=function(window) {
  658.     //dump("[Core] registerWindow("+window+")\n");
  659.     this.monitorWindow(window);
  660. }
  661.     
  662. Core.prototype.unregisterWindow=function(window) {
  663.     //dump("[Core] unregisterWindow("+window+")\n");
  664.     try {
  665.         var tbd=[];
  666.         for(var i in this.entries) {
  667.             var entry=this.entries[i];
  668.             if(entry.has("window")) {
  669.                 var entryWindow=entry.get("window",Components.interfaces.nsIDOMWindow);
  670.                 if(entryWindow==window) {
  671.                     tbd.push(entry);
  672.                 }
  673.             }
  674.         }
  675.         for(var i in tbd) {
  676.             this.entries.splice(this.entries.indexOf(tbd[i]),1);
  677.         }
  678.     } catch(e) {
  679.         dump("!!! [Core] unregisterWindow: "+e+"\n");
  680.     }
  681. }
  682.     
  683. Core.prototype.monitorWindow=function(win) {
  684.     try {
  685.  
  686.         //dump("[Core] monitorWindow("+win+")\n");
  687.  
  688.         if(win.gBrowser) {
  689.             var mPanCont=win.gBrowser.mPanelContainer;
  690.             if(mPanCont) {
  691.                 mPanCont=mPanCont.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  692.                 mPanCont.addEventListener("select",this,false,false);
  693.             }
  694.         }
  695.         
  696.         function Listener(core) {
  697.             this.core=core;
  698.         }
  699.         Listener.prototype={
  700.             handleEvent: function(event) {
  701.                 if(event.target.id=="contentAreaContextMenu" || event.target.getAttribute("dwhelper-monitored-context-submenu")=="true")
  702.                     this.core.contextMenuOpened(event);
  703.             }
  704.         }
  705.         win.document.getElementById("contentAreaContextMenu").
  706.             QueryInterface(Components.interfaces.nsIDOMNSEventTarget).
  707.             addEventListener("popupshowing",new Listener(this),false,false);
  708.  
  709.         win=win.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  710.         //win.addEventListener("load",this,false,false);
  711.         
  712.         function WindowMonitor(window,core) {
  713.             this.window=window;
  714.             this.core=core;
  715.         }
  716.         WindowMonitor.prototype={
  717.             handleEvent: function(event) {
  718.                 switch(event.type) {
  719.                     case "pageshow":
  720.                         try {
  721.                             //dump("pageshow - "+event.target.URL+" "+event.target+"\n");
  722.                             var document=event.target.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
  723.                             this.core.updateEntriesForDocument(document,this.window);
  724.                             try {
  725.                                 var hook=Components.classes["@downloadhelper.net/dom-hook;1"]
  726.                                                             .getService(Components.interfaces.dhIDOMHook);
  727.                                 hook.hook(document);
  728.                             } catch(e) {
  729.                                 dump("!!! [Core] monitorWindow/hook: "+e+"\n");
  730.                             }
  731.                             this.core.updateMenus(document,this.window);
  732.                         } catch(e) {}
  733.                         break;
  734.                     case "pagehide":
  735.                         try {
  736.                             //dump("pagehide - "+event.target.URL+"\n");
  737.                             var document=event.target;
  738.                             this.core.cleanupEntriesForDocument(document,this.window);
  739.                             this.core.updateMenus(document,this.window);
  740.                         } catch(e) {}
  741.                         break;
  742.                 }
  743.             }
  744.         }
  745.         var windowMonitor=new WindowMonitor(win,this)
  746.         win.addEventListener("pageshow",windowMonitor,false,false);
  747.         win.addEventListener("pagehide",windowMonitor,false,false);
  748.         
  749.     } catch(e) {
  750.         dump("!!! [Core] monitorWindow: "+e+"\n");
  751.     }
  752. }
  753.  
  754. Core.prototype.registerProcessor=function(processor) {
  755.     for(var i in this.processors) {
  756.         if(this.processors[i].name==processor.name) {
  757.             this.processors[i]=processor;
  758.             return;
  759.         }
  760.     }
  761.     this.processors.push(processor);
  762. }
  763.  
  764. Core.prototype.unregisterProcessor=function(processor) {
  765.     this.processors.splice(this.processors.indexOf(processor),1);
  766. }
  767.  
  768. Core.prototype.handleCommand=function(entry,key) {
  769.     try {
  770.         //dump("[Core] handleCommand(entry,"+key+")\n");
  771.         var processor=null;
  772.         var procName=this.processorKeyMap[key];
  773.         if(procName) {
  774.             for(var i in this.processors) {
  775.                 if(this.processors[i].enabled && this.processors[i].name==procName) {
  776.                     processor=this.processors[i];
  777.                     break;
  778.                 }
  779.             }
  780.         }
  781.         if(processor==null) {
  782.             var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  783.                                         .getService(Components.interfaces.nsIWindowMediator);
  784.             var w = wm.getMostRecentWindow("navigator:browser");
  785.             var processors=[];
  786.             for(var i in this.processors) {
  787.                 if(this.processors[i].enabled) {
  788.                     processors.push({
  789.                         processor: this.processors[i],
  790.                         canHandle: this.processors[i].canHandle(entry)
  791.                     });
  792.                 }
  793.             }
  794.             var data={ 
  795.                 processors: processors,
  796.             };
  797.             w.openDialog('chrome://dwhelper/content/pick-processor.xul','dwhelper-dialog',"chrome,centerscreen,modal",data);
  798.             //dump("[Core] handleCommand(entry,"+key+") processor: "+data.processor+"\n");
  799.             var procName=data.processor;
  800.             for(var i in this.processors) {
  801.                 if(this.processors[i].enabled && this.processors[i].name==procName) {
  802.                     processor=this.processors[i];
  803.                     break;
  804.                 }
  805.             }
  806.         }
  807.         if(processor==null)
  808.             return;
  809.         this.processEntry(processor,entry);
  810.     } catch(e) {
  811.         dump("!!! [Core] handleCommand(entry,"+key+"): "+e+"\n");
  812.     }
  813. }
  814.  
  815. Core.prototype.updateBlackList=function() {
  816.     var blacklistPref=this.pref.getCharPref("media-host-blacklist");
  817.     this.blacklist=blacklistPref.split("|");
  818.     var entries=[];
  819.     var needUpdate=false;
  820.     for(var i in this.entries) {
  821.         if(this.filterBlackList(this.entries[i]))
  822.             entries.push(this.entries[i]);
  823.         else
  824.             needUpdate=true;
  825.     }
  826.     this.entries=entries;
  827.     if(needUpdate)
  828.         this.updateMenus(null,null);
  829. }
  830.  
  831. Core.prototype.shareBlackList=function() {
  832.     if(this.pref.getBoolPref("share-blacklist")) {
  833.         var now=new Date().getTime();
  834.         var lastShared=parseInt(this.pref.getCharPref("last-shared-blacklist"));
  835.         if(now-lastShared<1000*60*60*24*7)
  836.             return;
  837.         this.pref.setCharPref("last-shared-blacklist",""+now);
  838.         var newDomains=[];
  839.         function map(arr) {
  840.             var obj={};
  841.             for(var i in arr) obj[arr[i]]=1;
  842.             return obj;
  843.         }
  844.         var currentDomains=map(this.pref.getCharPref("media-host-blacklist").split("|"));
  845.         var lastDomains=map(this.pref.getCharPref("last-media-host-blacklist").split("|"));
  846.         for(var domain in currentDomains) {
  847.             if(!(domain in lastDomains)) {
  848.                 newDomains.push(domain);
  849.             }
  850.         }
  851.         this.pref.setCharPref("last-media-host-blacklist",this.pref.getCharPref("media-host-blacklist"));
  852.         if(newDomains.length>0) {
  853.             var xml="<?xml version='1.0'?>\n<blacklist-domains>\n";
  854.             for(var i in newDomains) {
  855.                 xml+="  <domain>"+newDomains[i]+"</domain>\n";
  856.             }
  857.             xml+="</blacklist-domains>";
  858.             var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
  859.                 createInstance(Components.interfaces.nsIXMLHttpRequest);
  860.             xmlhttp.open("POST", "http://www.downloadhelper.net/share-blacklist.php")
  861.             xmlhttp.send(xml);
  862.         }
  863.     }
  864. }
  865.  
  866. Core.prototype.updateProcessorKeyMap=function() {
  867.     //dump("[Core] updateProcessorKeyMap()\n");
  868.     this.processorKeyMap={}
  869.     var keymap="0:download,2:convert-choice,3:quick-download";
  870.     try {
  871.         keymap=this.pref.getCharPref("processor-keymap");
  872.     } catch(e) {}
  873.     var parts=keymap.split(",");
  874.     for(var i in parts) {
  875.         var parts2=parts[i].split(":");
  876.         if(parts2.length==2 && /^[0-9]+$/.test(parts2[0]) && parts2[1].length>0) {
  877.             this.processorKeyMap[parseInt(parts2[0])]=parts2[1];
  878.         }
  879.     }
  880.     //dump("[Core] updateProcessorKeyMap():\n");
  881.     //this.dumpObject(this.processorKeyMap);
  882. }
  883.  
  884. Core.prototype.downloadFinished=function(status, request, entry, ctx) {
  885.     //dump("[Core] downloadFinished("+status+",...)\n");
  886.     if(status==0) {
  887.         var format=Util.getPropsString(entry,"format");
  888.         if(format) {
  889.             var file;
  890.             if(entry.has("cv-file")) {
  891.                 file=entry.get("cv-file",Components.interfaces.nsILocalFile);
  892.             } else {
  893.                  file=Components.classes["@mozilla.org/file/directory_service;1"]
  894.                                          .getService(Components.interfaces.nsIProperties)
  895.                                          .get("TmpD", Components.interfaces.nsILocalFile);
  896.                  file.append("dwhelper-cv");
  897.                  file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
  898.                  entry.set("cv-file",file);                
  899.             }
  900.             this.cvMgr.addConvert(entry.get("dl-file",Components.interfaces.nsILocalFile),file,format,true,this,entry,ctx);
  901.         } else {
  902.             var processor=ctx.QueryInterface(Components.interfaces.dhIProcessor);
  903.             processor.handle(entry);
  904.         }
  905.     }
  906. }
  907.  
  908. Core.prototype.conversionFinished=function(status, entry, ctx) {
  909.     //dump("[Core] conversionFinished("+status+",...)\n");
  910.     if(status) {
  911.         var processor=ctx.QueryInterface(Components.interfaces.dhIProcessor);
  912.         processor.handle(entry);
  913.     }
  914. }
  915.  
  916. Core.prototype.getProcessors=function() {
  917.     var processors=Components.classes["@mozilla.org/array;1"].
  918.         createInstance(Components.interfaces.nsIMutableArray);
  919.     for(var i in this.processors) {
  920.         if(this.processors[i].enabled)
  921.             processors.appendElement(this.processors[i],false);
  922.     }
  923.     return processors.QueryInterface(Components.interfaces.nsIArray)
  924. }
  925.  
  926. Core.prototype.updateSystemMenu=function(menupopup) {
  927.     
  928.     try {
  929.     
  930.     this.clearMenu(menupopup);
  931.         
  932.     var systemMenuData=[
  933.         { 
  934.             label: Util.getText("menu.preferences"),
  935.             image: "chrome://dwhelper/skin/icon-pref.png",
  936.             type: "dialog",
  937.             modal: false,
  938.             toolbar: true,
  939.             url: "chrome://dwhelper/content/preferences-new.xul"
  940.         },
  941.         { 
  942.             label: Util.getText("menu.sites"),
  943.             type: "dialog",
  944.             url: "chrome://dwhelper/content/sites.xul"
  945.         },
  946.         { 
  947.             label: Util.getText("menu.history"),
  948.             type: "dialog",
  949.             modal: false,
  950.             url: "chrome://dwhelper/content/history.xul",
  951.             cond: "isHistoryEnabled"
  952.         },
  953.         { 
  954.             label: Util.getText("menu.convert-register"),
  955.             image: "chrome://dwhelper/skin/converter-12x12.png",
  956.             type: "dialog",
  957.             modal: false,
  958.             url: "chrome://dwhelper/content/convert-register.xul",
  959.             cond: "conversionNeedsRegistration"
  960.         },
  961.         { 
  962.             label: Util.getText("menu.manual-convert"),
  963.             image: "chrome://dwhelper/skin/converter-12x12.png",
  964.             type: "method",
  965.             method: "manualConvert",
  966.             cond: "isConversionEnabled"
  967.         },
  968.         { 
  969.             label: Util.getText("menu.converter-queue"),
  970.             image: "chrome://dwhelper/skin/converter-12x12.png",
  971.             type: "dialog",
  972.             modal: false,
  973.             url: "chrome://dwhelper/content/converter-queue.xul",
  974.             cond: "isConversionEnabled"
  975.         },
  976.         { 
  977.             label: Util.getText("menu.download-queue"),
  978.             type: "dialog",
  979.             modal: false,
  980.             url: "chrome://dwhelper/content/download-queue.xul",
  981.             cond: "useDownloadQueue"
  982.         },
  983.         { 
  984.             label: Util.getText("menu.open-download-dir"),
  985.             type: "method",
  986.             method: "openDownloadDirectory",
  987.         },
  988.         { 
  989.             label: Util.getText("menu.search-videos"),
  990.             type: "method",
  991.             method: "searchVideos",
  992.         },
  993.         { 
  994.             label: Util.getText("menu.search-adult-videos"),
  995.             type: "method",
  996.             method: "searchAdultVideos",
  997.             cond: "isAdultEnabled"
  998.         },
  999.         { 
  1000.             label: Util.getText("mp3tunes.label.open-mp3tunes-locker"),
  1001.             image: "chrome://dwhelper/skin/mp3tunes-16x16.png",
  1002.             type: "method",
  1003.             method: "openMP3TunesLocker",
  1004.             cond: "isMP3TunesEnabled"
  1005.         },
  1006.         { 
  1007.             label: Util.getText("menu.help"),
  1008.             image: "chrome://dwhelper/skin/icon-help.png",
  1009.             type: "opentab",
  1010.             url: "http://www.downloadhelper.net/manual.php",
  1011.         },
  1012.         { 
  1013.             label: Util.getText("menu.knowledge-base"),
  1014.             type: "opentab",
  1015.             url: "http://www.downloadhelper.net/support-kb.php",
  1016.         },
  1017.         { 
  1018.             label: Util.getText("menu.tutorial-videos"),
  1019.             type: "opentab",
  1020.             url: "http://www.downloadhelper.net/tutorials.php",
  1021.         },
  1022.         { 
  1023.             type: "separator"
  1024.         },
  1025.         { 
  1026.             label: Util.getText("menu.subtile.extension"),
  1027.             image: "chrome://dwhelper/skin/icon-subtile.png",
  1028.             type: "menu",
  1029.             menu: [
  1030.                 {
  1031.                     label: Util.getText("menu.subtile.install"),
  1032.                     type: "opentab",
  1033.                     url: "http://www.downloadhelper.net/dh-st-install.php",
  1034.                 },
  1035.                 {
  1036.                     label: Util.getText("menu.subtile.monitor-video-sites"),
  1037.                     type: "opentab",
  1038.                     url: "http://www.downloadhelper.net/dh-monitor-vsites.php",
  1039.                 },
  1040.                 {
  1041.                     label: Util.getText("menu.subtile.cust-monitor-video-sites"),
  1042.                     type: "opentab",
  1043.                     url: "http://www.downloadhelper.net/dh-st-build.php",
  1044.                 },
  1045.                 {
  1046.                     label: Util.getText("menu.subtile.create-menu"),
  1047.                     type: "opentab",
  1048.                     url: "http://www.downloadhelper.net/dh-create.php",
  1049.                    },
  1050.                ]
  1051.            },
  1052.         { 
  1053.             label: Util.getText("menu.media"),
  1054.             type: "downloadmenu",
  1055.         },
  1056.         { 
  1057.             type: "separator"
  1058.         },
  1059.         { 
  1060.             label: Util.getText("menu.about"),
  1061.             image: "chrome://dwhelper/skin/icon-about.png",
  1062.             type: "dialog",
  1063.             modal: false,
  1064.             url: "chrome://dwhelper/content/about.xul"
  1065.            }
  1066.     ];
  1067.     this.updateSystemMenuLevel(menupopup,systemMenuData);
  1068.     } catch(e) {
  1069.         dump("!!! [Core] updateSystemMenu(): "+e+"\n");
  1070.     }
  1071. }
  1072.  
  1073. Core.prototype.updateSystemMenuLevel=function(menupopup,menuData) {    
  1074.     var document=menupopup.ownerDocument;
  1075.     var useIcons=this.pref.getBoolPref("system-menu-icons");
  1076.     for(var i in menuData) {
  1077.         var mData=menuData[i];
  1078.         switch(mData.type) {
  1079.             case "dialog":
  1080.             case "method":
  1081.             case "opentab":
  1082.                 if(mData.cond) {
  1083.                     if(!this[mData.cond](mData))
  1084.                         continue;
  1085.                 }
  1086.                 function Listener(core,data) {
  1087.                     this.core=core;
  1088.                     this.data=data;
  1089.                 }
  1090.                 Listener.prototype={
  1091.                     handleEvent: function(event) {
  1092.                         if(event.type=="command") {
  1093.                             var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1094.                                                         .getService(Components.interfaces.nsIWindowMediator);
  1095.                             var window = wm.getMostRecentWindow("navigator:browser");
  1096.                             switch(this.data.type) {
  1097.                                 case "dialog":
  1098.                                     var options="chrome,centerscreen,titlebar";
  1099.                                     if(this.data.toolbar==null || this.data.toolbar!=false)
  1100.                                         options+=",toolbar";
  1101.                                     if(this.data.modal==null || this.data.modal!=false)
  1102.                                         options+=",modal";
  1103.                                     window.openDialog(this.data.url,'_blank',options, {} );
  1104.                                     break;
  1105.                                 case "method":
  1106.                                     this.core[this.data.method](this.data);
  1107.                                     break;
  1108.                                 case "opentab":
  1109.                                     var browser=window.getBrowser();
  1110.                                     browser.selectedTab=browser.addTab(this.data.url);
  1111.                                     break;
  1112.                             }
  1113.                         }
  1114.                     }
  1115.                 }
  1116.                 var classes=[];
  1117.                 var menuitem=document.createElement("menuitem");
  1118.                 menuitem.setAttribute("label",mData.label);
  1119.                 if(mData.image) {
  1120.                     if(useIcons) {
  1121.                         classes.push("menuitem-iconic");
  1122.                         menuitem.setAttribute("image",mData.image);
  1123.                     }
  1124.                 }
  1125.                 menuitem.setAttribute("class",classes.join(" "));
  1126.                 menupopup.appendChild(menuitem);
  1127.                 menuitem=menuitem.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  1128.                 menuitem.addEventListener("command",new Listener(this,mData),false,false);
  1129.                 break;
  1130.                 
  1131.             case "separator":
  1132.                 var menuseparator=document.createElement("menuseparator");
  1133.                 menupopup.appendChild(menuseparator);                
  1134.                 break;
  1135.                 
  1136.             case "menu":
  1137.                 var classes=[];
  1138.                 var menu=document.createElement("menu");
  1139.                 menu.setAttribute("label",mData.label);
  1140.                 if(mData.image) {
  1141.                     if(useIcons) {
  1142.                         classes.push("menu-iconic");
  1143.                         menu.setAttribute("image",mData.image);
  1144.                     }
  1145.                 }
  1146.                 menu.setAttribute("class",classes.join(" "));
  1147.                 menupopup.appendChild(menu);
  1148.                 var menupopup0=document.createElement("menupopup");
  1149.                 menu.appendChild(menupopup0);
  1150.                 this.updateSystemMenuLevel(menupopup0,mData.menu);
  1151.                 break;
  1152.  
  1153.             case "downloadmenu":
  1154.                 var menu=document.createElement("menu");
  1155.                 menu.setAttribute("label",mData.label);
  1156.                 menupopup.appendChild(menu);
  1157.                 var menupopup0=document.createElement("menupopup");
  1158.                 menupopup0.setAttribute("hide-parent-if-empty","true");
  1159.                 menu.appendChild(menupopup0);
  1160.                 function Listener(core,menupopup,target) {
  1161.                     this.core=core;
  1162.                     this.menupopup=menupopup;
  1163.                     this.target=target;
  1164.                 }
  1165.                 Listener.prototype={
  1166.                     handleEvent: function(event) {
  1167.                         if(event.type=="popuphiding" && event.target==this.target) {
  1168.                             this.core.unregisterMenu(this.menupopup);
  1169.                             this.menupopup.parentNode.parentNode.removeChild(this.menupopup.parentNode);
  1170.                         }
  1171.                     }
  1172.                 }
  1173.                 menupopup.addEventListener("popuphiding",new Listener(this,menupopup0,menupopup),false,false);
  1174.                 this.registerMenu(menupopup0,Components.interfaces.dhICore.MENU_TYPE_DOWNLOAD);
  1175.                 break;
  1176.         }
  1177.     }
  1178. }
  1179.  
  1180. Core.prototype.isHistoryEnabled=function(data) {
  1181.     var he=false;
  1182.     try {
  1183.         he=this.pref.getBoolPref("history-enabled");
  1184.     } catch(e) {}
  1185.     return he;
  1186. }
  1187.  
  1188. Core.prototype.conversionNeedsRegistration=function(data) {
  1189.     var cvInfo=this.cvMgr.getInfo();
  1190.     if(!cvInfo.get("windows",Components.interfaces.nsISupportsPRBool).data)
  1191.         return false;
  1192.     if(!cvInfo.get("enabled",Components.interfaces.nsISupportsPRBool).data)
  1193.         return false;
  1194.     return cvInfo.get("unregistered",Components.interfaces.nsISupportsPRBool).data;
  1195. }
  1196.  
  1197. Core.prototype.isConversionEnabled=function(data) {
  1198.     var cvInfo=this.cvMgr.getInfo();
  1199.     return cvInfo.get("enabled",Components.interfaces.nsISupportsPRBool).data;
  1200. }
  1201.  
  1202. Core.prototype.isMP3TunesEnabled=function(data) {
  1203.     return this.pref.getBoolPref("mp3tunes.enabled");
  1204. }
  1205.  
  1206. Core.prototype.isOneByOne=function(data) {
  1207.     var dm="onebyone";
  1208.     try {
  1209.         dm=this.pref.getCharPref("download-mode");
  1210.     } catch(e) {}
  1211.     return (dm=="onebyone");
  1212. }
  1213.  
  1214. Core.prototype.useDownloadQueue=function(data) {
  1215.     var dm="onebyone";
  1216.     try {
  1217.         dm=this.pref.getCharPref("download-mode");
  1218.     } catch(e) {}
  1219.     return (dm=="onebyone" || dm=="controlled");
  1220. }
  1221.  
  1222. Core.prototype.openDownloadDirectory=function(data) {
  1223.     //dump("openDownloadDirectory()\n");
  1224.     try {
  1225.         var dir=this.dlMgr.getDownloadDirectory().QueryInterface(Components.interfaces.nsILocalFile);
  1226.         dir.reveal();
  1227.     } catch(e) {}
  1228. }
  1229.  
  1230. Core.prototype.openMP3TunesLocker=function(data) {
  1231.     function AuthObserver() {
  1232.     }
  1233.     AuthObserver.prototype={
  1234.         observe: function(subject,topic,data) {
  1235.             var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1236.                                         .getService(Components.interfaces.nsIWindowMediator);
  1237.             var window = wm.getMostRecentWindow("navigator:browser");
  1238.             if(topic=="mp3tunes-auth-succeeded") {
  1239.                 var browser=window.getBrowser();
  1240.                 browser.selectedTab=browser.addTab("http://www.mp3tunes.com/player/");
  1241.             } else {
  1242.                 window.alert(Util.getText("mp3tunes.error.no-login-check-credentials"));
  1243.             }
  1244.         }
  1245.     }
  1246.     var mtMgr=Components.classes["@downloadhelper.net/mp3tunes-manager;1"]
  1247.                                   .getService(Components.interfaces.dhIMP3Tunes);
  1248.     var username=this.pref.getCharPref("mp3tunes.username");
  1249.     var password=Util.getPassword("mp3tunes");
  1250.     if(password==null) password="";
  1251.     mtMgr.authenticate(username,password,new AuthObserver());
  1252. }
  1253.  
  1254. Core.prototype.openDownloadDirectoryCommand=function() {
  1255.     //dump("[Core] openDownloadDirectoryCommand()\n");
  1256.     this.openDownloadDirectory(null);
  1257. }
  1258.  
  1259. Core.prototype.quickDownloadCommand=function() {
  1260.     //dump("[Core] quickDownloadCommand()\n");
  1261.     try {
  1262.         var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].getService().
  1263.             QueryInterface(Components.interfaces.nsIWindowWatcher);
  1264.         var aWindow=wwatch.activeWindow;
  1265.         if(aWindow==null || aWindow.content==null || aWindow.content.document==null || aWindow.content.document.URL==null)
  1266.             return;
  1267.         var url=aWindow.content.document.URL;
  1268.         var foundEntry=null;
  1269.         var mostRecent=0;
  1270.         for(var i in this.entries) {
  1271.             var entry=this.entries[i];
  1272.             if(Util.getPropsString(entry,"entry-type")=="expirable" &&
  1273.                 Util.getPropsString(entry,"page-url")==url) {
  1274.                 var creationDate=parseInt(Util.getPropsString(entry,"creation-date"));
  1275.                 if(creationDate>mostRecent) {
  1276.                     creationDate=mostRecent;
  1277.                     foundEntry=entry;
  1278.                 }
  1279.             }
  1280.         }
  1281.         if(foundEntry) {
  1282.             this.quickProcess(foundEntry);
  1283.         } else {
  1284.             this.promptService.alert(null,"DownloadHelper",Util.getText("error.quickkey.nohit"));
  1285.         }
  1286.     } catch(e) {
  1287.         dump("!!! [Core] quickDownloadCommand(): "+e+"\n");
  1288.     }
  1289. }
  1290.  
  1291. Core.prototype.manualConvert=function(data) {
  1292.     try {
  1293.         var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1294.                                     .getService(Components.interfaces.nsIWindowMediator);
  1295.         var window = wm.getMostRecentWindow("navigator:browser");
  1296.         var filePicker=Components.classes["@mozilla.org/filepicker;1"]
  1297.                                           .createInstance(Components.interfaces.nsIFilePicker);
  1298.            filePicker.init(window,Util.getText("title.files-to-convert"), 
  1299.                Components.interfaces.nsIFilePicker.modeOpenMultiple);
  1300.            var dir=this.dlMgr.getDownloadDirectory();
  1301.            filePicker.displayDirectory=dir;
  1302.            filePicker.appendFilter("FLV","*.flv; *.FLV");
  1303.            filePicker.appendFilter("Video","*.flv; *.FLV; *.avi; *.AVI; *.mpeg; *.MPEG; *.mpg; *.MPG; *.wmv; *.WMV; *.rm; *.RM; *.mov; *.MOV; *.mp4; *.MP4");
  1304.            filePicker.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
  1305.            var r=filePicker.show();
  1306.            if(r==Components.interfaces.nsIFilePicker.returnCancel)
  1307.                return;
  1308.                
  1309.         var data={};
  1310.         window.openDialog("chrome://dwhelper/content/convert-manual.xul",
  1311.                      "dwhelper-convert-manual", "chrome,centerscreen,modal",data);
  1312.         if(data.format==null) {
  1313.             return;
  1314.         }
  1315.  
  1316.            var i=filePicker.files;
  1317.            while(i.hasMoreElements()) {
  1318.                var file=i.getNext().QueryInterface(Components.interfaces.nsIFile);
  1319.                var targetFile=file.parent;
  1320.                targetFile.append(this.cvMgr.getConvertedFileName(file.leafName,data.format));
  1321.                this.cvMgr.addConvert(file,targetFile,data.format,false,null,null,null);
  1322.            }
  1323.     } catch(e) {
  1324.         dump("!!! [Core] manualConvert():"+e+"\n");
  1325.     }
  1326. }
  1327.  
  1328. Core.prototype.buttonClicked=function(window) {
  1329.     var action=this.pref.getCharPref("icon-click");
  1330.     if(action=="sites") {
  1331.         var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1332.                                     .getService(Components.interfaces.nsIWindowMediator);
  1333.         var window = wm.getMostRecentWindow("navigator:browser");
  1334.         window.open("chrome://dwhelper/content/sites.xul",
  1335.                 "dwhelper-sites", "chrome,centerscreen,resizable=yes").focus();
  1336.     } else if(action=="quick-download") {
  1337.         this.quickDownloadCommand();
  1338.     }
  1339. }
  1340.  
  1341. Core.prototype.registerContextItem=function(item) {
  1342.     //dump("[Core] registerContextItem("+item.tagName+")\n");
  1343.     try {
  1344.         var service=Components.classes[item.getAttribute("context-item-handler")].
  1345.             getService(Components.interfaces.dhIContextItem);
  1346.         var itemData={
  1347.                 item: item,
  1348.                 window: item.ownerDocument.defaultView,
  1349.                 service: service 
  1350.         };
  1351.         this.ctxItems.push(itemData);
  1352.         function Listener(itemData) {
  1353.             this.itemData=itemData;
  1354.         }
  1355.         Listener.prototype={
  1356.             handleEvent: function(event) {
  1357.                 var window=event.target.ownerDocument.defaultView;
  1358.                 this.itemData.service.handle(window.content.document,window,this.itemData.item);
  1359.             }
  1360.         }
  1361.         item=item.QueryInterface(Components.interfaces.nsIDOMNSEventTarget);
  1362.         item.addEventListener("command",new Listener(itemData),false,false);
  1363.     } catch(e) {
  1364.         dump("!!! [Core] registerContextItem(): "+e+"\n");
  1365.     }
  1366. }
  1367.  
  1368. Core.prototype.unregisterContextItem=function(item) {
  1369.     //dump("[Core] unregisterContextItem("+item.tagName+")\n");
  1370.     for(var i in this.ctxItems) {
  1371.         if(this.ctxItems[i].item==item) {
  1372.             this.ctxItem.splice(i,1);
  1373.             break;
  1374.         }
  1375.     }
  1376. }
  1377.  
  1378. Core.prototype.contextMenuOpened=function(event) {
  1379.     //dump("[Core] contextMenuOpened()\n");
  1380.     try {
  1381.         var window=event.target.ownerDocument.defaultView;
  1382.         for(var i in this.ctxItems) {
  1383.             var ctxItem=this.ctxItems[i];
  1384.             if(window==ctxItem.window) {
  1385.                 var canHandle=ctxItem.service.canHandle(window.content.document,window,ctxItem.item);
  1386.                 if(canHandle)
  1387.                     ctxItem.item.setAttribute("hidden","false");
  1388.                 else
  1389.                     ctxItem.item.setAttribute("hidden","true");
  1390.             }
  1391.         }
  1392.     } catch(e) {
  1393.         dump("!!! [Core] contextMenuOpened(): "+e+"\n");
  1394.     }
  1395. }
  1396.  
  1397. Core.prototype.quickProcess=function(entry) {
  1398.     //dump("[Core] quickProcess()\n");
  1399.     var quickProcessor="quick-download";
  1400.     try {
  1401.     } catch(e) {
  1402.         quickProcessor=this.pref.getCharPref("quick-processor");
  1403.     }
  1404.     var processor=null;
  1405.     for(var i in this.processors) {
  1406.         if(this.processors[i].enabled && this.processors[i].name==quickProcessor) {
  1407.             processor=this.processors[i];
  1408.             break;
  1409.         }
  1410.     }
  1411.     if(processor==null) {
  1412.         dump("!!! [Core] quickProcess(): no processor for "+quickProcessor+"\n");
  1413.         return;
  1414.     }
  1415.     this.processEntry(processor,entry);
  1416. }
  1417.  
  1418. Core.prototype.processEntry=function(processor,entry) {
  1419.     entry=this.cloneEntry(entry);
  1420.     if(processor.canHandle(entry)) {
  1421.         if(processor.requireDownload(entry)) {
  1422.             if(processor.preDownload(entry)==false)
  1423.                 return;
  1424.             var mediaUrl=Util.getPropsString(entry,"media-url");
  1425.             if(mediaUrl)
  1426.                 this.listMgr.addCurrentURL(mediaUrl);
  1427.             this.dlMgr.download(this,entry,processor);
  1428.         } else {
  1429.             processor.handle(entry);
  1430.         }
  1431.     }    
  1432. }
  1433.  
  1434. Core.prototype.cloneEntry=function(entry) {
  1435.     var entry0=Components.classes["@mozilla.org/properties;1"].
  1436.         createInstance(Components.interfaces.nsIProperties);
  1437.     var keys=entry.getKeys({});
  1438.     for(var i in keys) {
  1439.         var key=keys[i];
  1440.         var value;
  1441.         try {
  1442.             value=entry.get(key,Components.interfaces.nsIArray);
  1443.             var array0=Components.classes["@mozilla.org/array;1"].
  1444.                 createInstance(Components.interfaces.nsIMutableArray);
  1445.             var j=value.enumerate();
  1446.             while(j.hasMoreElements()) {
  1447.                 var entry1=j.getNext().QueryInterface(Components.interfaces.nsIProperties);
  1448.                 array0.appendElement(this.cloneEntry(entry1),false);
  1449.             }
  1450.             value=array0;
  1451.         } catch(e) {
  1452.             value=entry.get(key,Components.interfaces.nsISupports);
  1453.         }
  1454.         entry0.set(key,value);
  1455.     }
  1456.     return entry0;
  1457. }
  1458.  
  1459. Core.prototype.removeDownloadCookie=function() {
  1460.     try {
  1461.         var cMgr = Components.classes["@mozilla.org/cookiemanager;1"].
  1462.            getService(Components.interfaces.nsICookieManager);
  1463.         try {
  1464.             cMgr.remove(".downloadhelper.net","dwcount","/",false);
  1465.         } catch(e) {}
  1466.         try {
  1467.             cMgr.remove(".vidohe.com","dwcount","/",false);
  1468.         } catch(e) {}
  1469.     } catch(e) {
  1470.     }
  1471.  
  1472. }
  1473.  
  1474. Core.prototype.getEntriesForDocument=function(document) {
  1475.     var entries=Components.classes["@mozilla.org/array;1"].
  1476.         createInstance(Components.interfaces.nsIMutableArray);
  1477.     for(var i in this.entries) {
  1478.         if(this.entries[i].has("document")) {
  1479.             var document0=this.entries[i].get("document",Components.interfaces.nsIDOMDocument);
  1480.             if(document0==document) {
  1481.                 entries.appendElement(this.entries[i],false);
  1482.             }
  1483.         }
  1484.     }
  1485.     return entries.QueryInterface(Components.interfaces.nsIArray)
  1486. }
  1487.  
  1488. Core.prototype.getEntries=function() {
  1489.     var entries=Components.classes["@mozilla.org/array;1"].
  1490.         createInstance(Components.interfaces.nsIMutableArray);
  1491.     for(var i in this.entries) {
  1492.         entries.appendElement(this.entries[i],false);
  1493.     }
  1494.     return entries.QueryInterface(Components.interfaces.nsIArray)
  1495. }
  1496.  
  1497. Core.prototype.searchVideos=function() {
  1498.     this.doSearchVideos(false);
  1499. }
  1500.  
  1501. Core.prototype.searchAdultVideos=function() {
  1502.     this.doSearchVideos(true);
  1503. }
  1504.  
  1505. Core.prototype.doSearchVideos=function(adult) {
  1506.     var dialogTitle=Util.getText(adult?"title.search-adult-videos":"title.search-videos");
  1507.     var query={}
  1508.     if(!this.promptService.prompt(null,dialogTitle,Util.getText("message.search-videos"),query,null,{}))
  1509.         return;
  1510.     var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1511.                                 .getService(Components.interfaces.nsIWindowMediator);
  1512.     var window = wm.getMostRecentWindow("navigator:browser");
  1513.     var browser=window.getBrowser();
  1514.     var url;
  1515.     if(adult)
  1516.         url="http://www.downloadhelper.net/videox-search-results.php?cx=005536796155304041479%3Ar9ep8ygv2ca&cof=FORID%3A11&from=dh-adult";
  1517.     else
  1518.         url="http://www.downloadhelper.net/video-search-results.php?cx=005536796155304041479%3Ahbixpuuu7l8&cof=FORID%3A11&from=dh-family";
  1519.     url+="&q="+window.escape(query.value);
  1520.     browser.selectedTab=browser.addTab(url);
  1521. }
  1522.  
  1523. Core.prototype.updateSmartName=function() {
  1524.     for(var i in this.entries)
  1525.         this.smartNamer.updateEntry(this.entries[i]);
  1526.     this.updateMenus(null,null);    
  1527. }
  1528.  
  1529. Core.prototype.isAdultEnabled=function() {
  1530.     var allowAdult=this.pref.getBoolPref("adult");
  1531.     var safeMode=false;
  1532.     try {
  1533.         safeMode=this.pref.getBoolPref("safe-mode");
  1534.     } catch(e) {}
  1535.     return safeMode==false && allowAdult;
  1536. }
  1537.  
  1538.  
  1539. Core.prototype.dumpObject=function(obj) {
  1540.     dump(obj+"\n");
  1541.     for(var field in obj) {
  1542.         dump("  "+field+": ");
  1543.         try {
  1544.         if(typeof(obj[field])=="function")
  1545.             dump("()");
  1546.         else
  1547.             dump(obj[field]);
  1548.          } catch(e) { dump("!!!"); }
  1549.         dump("\n");
  1550.     }
  1551. }
  1552.  
  1553. Core.prototype.QueryInterface = function(iid) {
  1554.     //dump("[Core] QueryInterface("+iid+")\n");
  1555.     if(
  1556.         iid.equals(Components.interfaces.dhICore)==false &&
  1557.         iid.equals(Components.interfaces.dhIDownloadListener)==false &&
  1558.         iid.equals(Components.interfaces.dhIConversionListener)==false &&
  1559.         iid.equals(Components.interfaces.nsIObserver)==false &&
  1560.         iid.equals(Components.interfaces.nsIDOMEventListener)==false &&
  1561.         iid.equals(Components.interfaces.nsISupports)==false
  1562.     ) {
  1563.             throw Components.results.NS_ERROR_NO_INTERFACE;
  1564.         }
  1565.     return this;
  1566. }
  1567.  
  1568. var vCoreModule = {
  1569.     firstTime: true,
  1570.     
  1571.     /*
  1572.      * RegisterSelf is called at registration time (component installation
  1573.      * or the only-until-release startup autoregistration) and is responsible
  1574.      * for notifying the component manager of all components implemented in
  1575.      * this module.  The fileSpec, location and type parameters are mostly
  1576.      * opaque, and should be passed on to the registerComponent call
  1577.      * unmolested.
  1578.      */
  1579.     registerSelf: function (compMgr, fileSpec, location, type) {
  1580.  
  1581.         if (this.firstTime) {
  1582.             this.firstTime = false;
  1583.             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  1584.         }
  1585.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1586.         compMgr.registerFactoryLocation(NS_CORE_CID,
  1587.                                         "Core",
  1588.                                         NS_CORE_PROG_ID, 
  1589.                                         fileSpec,
  1590.                                         location,
  1591.                                         type);
  1592.     },
  1593.  
  1594.     unregisterSelf: function(compMgr, fileSpec, location) {
  1595.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  1596.         compMgr.unregisterFactoryLocation(NS_DH_CORE_CID, fileSpec);
  1597.     },
  1598.  
  1599.     /*
  1600.      * The GetClassObject method is responsible for producing Factory and
  1601.      * SingletonFactory objects (the latter are specialized for services).
  1602.      */
  1603.     getClassObject: function (compMgr, cid, iid) {
  1604.         if (!cid.equals(NS_CORE_CID)) {
  1605.             throw Components.results.NS_ERROR_NO_INTERFACE;
  1606.         }
  1607.  
  1608.         if (!iid.equals(Components.interfaces.nsIFactory)) {
  1609.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1610.         }
  1611.  
  1612.         return this.vCoreFactory;
  1613.     },
  1614.  
  1615.     /* factory object */
  1616.     vCoreFactory: {
  1617.         /*
  1618.          * Construct an instance of the interface specified by iid, possibly
  1619.          * aggregating it with the provided outer.  (If you don't know what
  1620.          * aggregation is all about, you don't need to.  It reduces even the
  1621.          * mightiest of XPCOM warriors to snivelling cowards.)
  1622.          */
  1623.         createInstance: function (outer, iid) {
  1624.             if (outer != null) {
  1625.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  1626.             }
  1627.     
  1628.             if(Util==null) 
  1629.                 Util=Components.classes["@downloadhelper.net/util-service;1"]
  1630.                     .getService(Components.interfaces.dhIUtilService);
  1631.  
  1632.             return new Core().QueryInterface(iid);
  1633.         }
  1634.     },
  1635.  
  1636.     /*
  1637.      * The canUnload method signals that the component is about to be unloaded.
  1638.      * C++ components can return false to indicate that they don't wish to be
  1639.      * unloaded, but the return value from JS components' canUnload is ignored:
  1640.      * mark-and-sweep will keep everything around until it's no longer in use,
  1641.      * making unconditional ``unload'' safe.
  1642.      *
  1643.      * You still need to provide a (likely useless) canUnload method, though:
  1644.      * it's part of the nsIModule interface contract, and the JS loader _will_
  1645.      * call it.
  1646.      */
  1647.     canUnload: function(compMgr) {
  1648.         return true;
  1649.     }
  1650. };
  1651.  
  1652. function NSGetModule(compMgr, fileSpec) {
  1653.     return vCoreModule;
  1654. }
  1655.  
  1656.